using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using AutoMapper;
using UwinEducation.Application.Common.Interfaces;
using UwinEducation.Application.Dtos;
using UwinEducation.Domain.Entities;
using UwinEducation.Domain.IRepositories;
using UwinEducation.Shared.Exceptions;
using UwinEducation.Shared.Models;

namespace UwinEducation.Application.Services
{
    /// <summary>
    /// 教师假期服务实现
    /// </summary>
    public class TeacherVacationService : ITeacherVacationService
    {
        private readonly ITeacherVacationRepository _teacherVacationRepository;
        private readonly ITeacherRepository _teacherRepository;
        private readonly ITeacherScheduleRepository _teacherScheduleRepository;
        private readonly IMapper _mapper;

        public TeacherVacationService(
            ITeacherVacationRepository teacherVacationRepository,
            ITeacherRepository teacherRepository,
            ITeacherScheduleRepository teacherScheduleRepository,
            IMapper mapper)
        {
            _teacherVacationRepository = teacherVacationRepository;
            _teacherRepository = teacherRepository;
            _teacherScheduleRepository = teacherScheduleRepository;
            _mapper = mapper;
        }

        /// <summary>
        /// 获取教师假期分页列表
        /// </summary>
        public async Task<PagedResult<TeacherVacationDto>> GetPagedListAsync(TeacherVacationPageRequest pageRequest)
        {
            var result = await _teacherVacationRepository.GetPagedListAsync(pageRequest);
            
            var dtos = _mapper.Map<List<TeacherVacationDto>>(result.Items);
            
            return new PagedResult<TeacherVacationDto>
            {
                Items = dtos,
                Total = result.Total
            };
        }

        /// <summary>
        /// 获取教师假期详情
        /// </summary>
        public async Task<TeacherVacationDto> GetByIdAsync(Guid id)
        {
            var vacation = await _teacherVacationRepository.GetDetailsByIdAsync(id);
            if (vacation == null)
            {
                throw new ArgumentException("教师假期不存在", id.ToString());
            }
            
            return _mapper.Map<TeacherVacationDto>(vacation);
        }

        /// <summary>
        /// 根据教师ID获取所有假期
        /// </summary>
        public async Task<List<TeacherVacationDto>> GetByTeacherIdAsync(Guid teacherId)
        {
            var vacations = await _teacherVacationRepository.GetByTeacherIdAsync(teacherId);
            return _mapper.Map<List<TeacherVacationDto>>(vacations);
        }

        /// <summary>
        /// 根据日期范围获取假期
        /// </summary>
        public async Task<List<TeacherVacationDto>> GetByDateRangeAsync(Guid teacherId, DateTime startDate, DateTime endDate)
        {
            var vacations = await _teacherVacationRepository.GetByDateRangeAsync(teacherId, startDate, endDate);
            return _mapper.Map<List<TeacherVacationDto>>(vacations);
        }

        /// <summary>
        /// 创建教师假期
        /// </summary>
        public async Task<TeacherVacationDto> CreateAsync(CreateTeacherVacationDto createDto)
        {
            // 1. 检查教师是否存在
            var teacher = await _teacherRepository.GetByIdAsync(createDto.TeacherId);
            if (teacher == null)
            {
                throw new ArgumentException("教师不存在", createDto.TeacherId.ToString());
            }

            // 2. 检查时间是否合理
            if (createDto.StartTime >= createDto.EndTime)
            {
                throw new ArgumentException("开始时间必须早于结束时间");
            }

            // 3. 检查时间是否有冲突
            var hasConflict = await _teacherVacationRepository.HasTimeConflictAsync(
                createDto.TeacherId,
                createDto.StartTime,
                createDto.EndTime
            );

            if (hasConflict)
            {
                throw new ArgumentException("该时间段已有其他假期安排");
            }

            // 4. 检查是否与课表冲突
            var hasScheduleConflict = await HasScheduleConflictAsync(
                createDto.TeacherId, 
                createDto.StartTime, 
                createDto.EndTime
            );

            if (hasScheduleConflict)
            {
                throw new ArgumentException("该时间段已有课程安排，请先调整课程");
            }

            // 5. 创建假期
            var vacation = TeacherVacation.Create(
                createDto.TeacherId,
                createDto.StartTime,
                createDto.EndTime,
                createDto.Reason ?? string.Empty
            );

            // 6. 保存假期
            await _teacherVacationRepository.AddAsync(vacation);

            return _mapper.Map<TeacherVacationDto>(vacation);
        }

        /// <summary>
        /// 更新教师假期
        /// </summary>
        public async Task<TeacherVacationDto> UpdateAsync(UpdateTeacherVacationDto updateDto)
        {
            // 1. 检查假期是否存在
            var vacation = await _teacherVacationRepository.GetByIdAsync(updateDto.Id);
            if (vacation == null)
            {
                throw new ArgumentException("教师假期不存在", updateDto.Id.ToString());
            }

            // 2. 检查时间是否有变更且合理
            DateTime startTime = updateDto.StartTime ?? vacation.StartTime;
            DateTime endTime = updateDto.EndTime ?? vacation.EndTime;

            if (startTime >= endTime)
            {
                throw new ArgumentException("开始时间必须早于结束时间");
            }

            // 3. 如果时间有变更，检查是否有冲突
            if (updateDto.StartTime.HasValue || updateDto.EndTime.HasValue)
            {
                var hasConflict = await _teacherVacationRepository.HasTimeConflictAsync(
                    vacation.TeacherId,
                    startTime,
                    endTime,
                    vacation.Id
                );

                if (hasConflict)
                {
                    throw new ArgumentException("该时间段已有其他假期安排");
                }

                // 4. 检查是否与课表冲突
                var hasScheduleConflict = await HasScheduleConflictAsync(
                    vacation.TeacherId, 
                    startTime, 
                    endTime
                );

                if (hasScheduleConflict)
                {
                    throw new ArgumentException("该时间段已有课程安排，请先调整课程");
                }
            }

            // 5. 更新假期
            vacation.StartTime = startTime;
            vacation.EndTime = endTime;

            if (updateDto.Reason != null)
            {
                vacation.Reason = updateDto.Reason;
            }

            // 6. 保存更新
            await _teacherVacationRepository.UpdateAsync(vacation);

            return _mapper.Map<TeacherVacationDto>(vacation);
        }

        /// <summary>
        /// 删除教师假期
        /// </summary>
        public async Task DeleteAsync(Guid id)
        {
            var vacation = await _teacherVacationRepository.GetByIdAsync(id);
            if (vacation == null)
            {
                throw new ArgumentException("教师假期不存在", id.ToString());
            }

            await _teacherVacationRepository.DeleteAsync(id);
        }

        /// <summary>
        /// 检查时间是否有冲突
        /// </summary>
        public async Task<bool> HasTimeConflictAsync(Guid teacherId, DateTime startTime, DateTime endTime, Guid? excludeId = null)
        {
            return await _teacherVacationRepository.HasTimeConflictAsync(teacherId, startTime, endTime, excludeId);
        }

        /// <summary>
        /// 检查是否与课表时间冲突
        /// </summary>
        private async Task<bool> HasScheduleConflictAsync(Guid teacherId, DateTime startTime, DateTime endTime)
        {
            // 获取教师在该时间段内的所有课表
            var schedules = await _teacherScheduleRepository.GetByTeacherIdInDateRangeAsync(
                teacherId, 
                startTime.Date, 
                endTime.Date
            );

            // 检查是否有课表时间与假期时间冲突
            foreach (var schedule in schedules)
            {
                foreach (var detail in schedule.TeacherScheduleDetails)
                {
                    // 判断课表明细时间是否与假期时间重叠
                    if (detail.StartTime <= endTime && detail.EndTime >= startTime)
                    {
                        return true; // 有冲突
                    }
                }
            }

            return false; // 没有冲突
        }
    }
} 